package com.cdream.basic.java8.io.biochat;

import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author cdream
 * @date 2022/8/16
 */
@Slf4j
public class ChatServer {
    private static final Integer PORT = 18080;
    private static final String HOST = "localhost";
    private static final String QUIT = "QUIT";
    private static final ConcurrentHashMap<Integer, Writer> map = new ConcurrentHashMap<>();
    private static final ExecutorService POOL = Executors.newFixedThreadPool(20);

    public static void main(String[] args) throws IOException {

        ServerSocket ss = new ServerSocket(PORT);
        while (true) {
            Socket accept = ss.accept();
            handler(accept);
        }
    }

    private static void handler(Socket accept) throws IOException {
        POOL.submit(() -> {
            addClient(accept);
            try {
                BufferedReader br = new BufferedReader(new InputStreamReader(accept.getInputStream()));
                String msg;
                while ((msg = br.readLine()) != null) {
                    log.info("收到客户端：{}发送信息：{}", accept.getPort(), msg);
                    if (isQuit(msg)) {
                        break;
                    }
                    sendMsg(accept, msg + "\n");
                }
            } catch (IOException e) {
                e.printStackTrace();
            } finally {
                removeClient(accept);
            }
        });


    }

    @SneakyThrows
    public static void addClient(Socket accept) {
        BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(accept.getOutputStream()));
        int port = accept.getPort();
        log.info("客户端：{}，上线啦", port);
        map.put(port, bw);
    }

    @SneakyThrows
    public static void sendMsg(Socket socket, String msg) {
        map.forEach((k, v) -> {
            if (socket.getPort() == k) {
                return;
            }
            try {
                v.write(msg);
                v.flush();
            } catch (IOException e) {
                e.printStackTrace();
            }
        });
    }

    public static boolean isQuit(String msg) {
        return "QUIT".equals(msg);
    }

    @SneakyThrows
    public static void removeClient(Socket accept) {
        int port = accept.getPort();

        Writer remove = map.remove(port);
        if (remove != null) {
            remove.close();
        }
        log.info("客户端：{}下线", port);
    }
}
